#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "string2.h"

/*--------------------------------------------------------------------------*/
/*  STRING.C								    */
/*    This class implements strings in C++, which can be created, assigned  */
/*    compared, and manipulated in an intuitive manner			    */
/*									    */
/*- Modification History ---------------------------------------------------*/
/*  When:	Who:			Comments:			    */
/*									    */
/*  05-Aug-93	Christopher G. Healey	Initial implementation		    */
/*              George Tsiknis						    */
/*  13-Oct-93	Christopher G. Healey	Added type conversions		    */
/*  24-Jan-94   Christopher G. Healey	Updates to ensure works properly    */
/*					with char arrays for ALL ops	    */
/*  03-Nov-94   Christopher G. Healey   Fixed is_int(), is_float() so that  */
/*					"+", "-" are not valid int/float    */
/*  26-Mar-95	Christopher G. Healey	Fixed 1 byte memory leak which	    */
/*					occurred in operator+() methods	    */
/*--------------------------------------------------------------------------*/


int string::is_int()

   //  This method returns TRUE if the string represents a valid integer,
   //  FALSE otherwise
{
   //  Ensure the characters in the string are only digits

   if ( size != strspn( str, "0123456789+-" ) ) {
      return 0;
   }

   //  Don't allow strings "+" or "-" to be treated as valid ints

   if ( ( str[ 0 ] == '+' || str[ 0 ] == '-' ) && size == 1 ) {
      return 0;
   }

   return 1;
}					// End method is_int


int string::is_float()

   //  This method returns TRUE if the string represents a valid float,
   //  FALSE otherwise
{
   //  Ensure the characters in the string are only digits or decimal place

   if ( size != strspn( str, "0123456789.+-" ) ) {
	  return 0;
   }

   //  Don't allow strings "+" or "-" to be treated as valid floats

   if ( ( str[ 0 ] == '+' || str[ 0 ] == '-' ) && size == 1 ) {
      return 0;
   }

   return 1;
}					// End method is_float


int string::len()

   //  This method returns the length of the given string
{
   return size;
}					// End method len


string string::substr( int a, int b )

   //  This method returns the substring in the range str[ a..b ]
   //
   //  a:  Start index of substring
   //  b:  End index of substring
{
   int     i;				// Loop counter
   string  ret_str;			// String object to return


   if ( a < 0 || a >= size || b < 0 || b >= size || a > b )
	  return ret_str;

   for( i = a; i <= b; i++ ) {		// Copy substring
      ret_str = ret_str + str[ i ];
   }

   return ret_str;
}					// End method substr


int string::operator==( const string& s )

   //  Compare operator for strings, returns TRUE if strings are equal,
   //  FALSE otherwise
   //
   //  s:  String to compare against
{
   return !strcmp( str, s.str );
}					// End operator ==


int string::operator!=( const string& s )

   //  Compare operator for strings, return TRUE if strings not equal,
   //  FALSE otherwise
   //
   //  s:  String to compare against
{
   return strcmp( str, s.str ) != 0;
}					// End operator !=


int string::operator<=( const string& s )

   //  Compare operator for strings, returns TRUE if string <= s,
   //  FALSE otherwise
   //
   //  s:  String to compare against
{
   return strcmp( str, s.str ) <= 0;
}					// End operator <=


int string::operator>=( const string& s )

   //  Compare operator for strings, returns TRUE if string >= s,
   //  FALSE otherwise
   //
   //  s:  String to compare against
{
   return strcmp( str, s.str ) >= 0;
}					// End operator >=


int string::operator<( const string& s )

   //  Compare operator for strings, returns TRUE if string < s,
   //  FALSE otherwise
   //
   //  s:  String to compare against
{
   return strcmp( str, s.str ) < 0;
}					// End operator <


int string::operator>( const string& s )

   //  Compare operator for strings, returns TRUE if string > s,
   //  FALSE otherwise
   //
   //  s:  String to compare against
{
   return strcmp( str, s.str ) > 0;
}					// End operator >


char& string::operator[]( int i )

   //  Indexing operator for strings, return reference to given element
   //
   //  i:  Index into string
{
   if ( i < 0 || i >= size ) {
      cerr << "Warning: String out of bounds\n";

      BOUNDS_ERR = -1;			// Reference to error character
      return BOUNDS_ERR;
   }

   return str[ i ];
}					// End operator []


string& string::operator=( const string& s )

   //  Assignment operator for strings, copy from already existing object
   //
   //  s:  String object to copy from
{
   if ( str ) {				// Free old string, if it exists
      delete str;
   }

   str = new char[ s.size + 1 ];	// Allocate memory for the string
   assert( str != NULL );

   size = s.size;			// Copy instance variable values
   strcpy( str, s.str );

   return *this;
}					// End operator =


string string::operator+( const string& s )

   //  This method concatenates the given string onto our string
   //
   //  s:  String to concatenate
{
   string  ret_str;			// String object to return


   delete ret_str.str;
   ret_str.str = new char[ size + s.size + 1 ];
   assert( ret_str.str != NULL );
   ret_str.str[ 0 ] = '\0';

   if ( size > 0 ) {
      strcpy( ret_str.str, str );	// Copy into string object
   }

   strcat( ret_str.str, s.str );

   ret_str.size = size + s.size;	// Set new string's length
   return ret_str;			// Return string object
}					// End operator +


string string::operator+( const char& c )

   //  This method concatenates the given character onto our string
   //
   //  c:  Character to concatenate
{
   char    arr[ 2 ];			// Array to hold char to concatenate
   string  ret_str;			// String object to return


   arr[ 0 ] = c;			// Create array with 1 char in it
   arr[ 1 ] = '\0';

   delete ret_str.str;
   ret_str.str = new char[ size + 2 ];
   assert( ret_str.str != NULL );
   ret_str.str[ 0 ] = '\0';

   if ( size > 0 ) {
      strcpy( ret_str.str, str );	// Copy into string object
   }

   strcat( ret_str.str, arr );

   ret_str.size = size + 1;		// Set new string's length
   return ret_str;			// Return string object
}					// End operator +


string::operator char*()

   //  This method provides automatic conversion from string to char *
{
   return str;
}					// End string to char * conversion


string::operator float()

   //  This method provides automatic conversion from string to float
{
   return atof( str );
}					// End string to float conversion


string::operator int()

   //  This method provides automatic conversion from string to integer
{
   return atoi( str );
}					// End string to int conversion


string::string()

   //  Constructor for strings, initialize instance variables
{
   str = new char[ 1 ];
   assert( str != NULL );

   str[ 0 ] = '\0';
   size = 0;
}					// End constructor method


string::string( const char *s )

   //  Constructor for strings, cast from a character array to a string
   //
   //  s:  Character array to cast from
{
   if ( !s ) {				// Assigning from NULL pointer
      str = new char[ 1 ];
      assert( str != NULL );

      str[ 0 ] = '\0';
      size = 0;

   } else {
      str = new char[ strlen( s ) + 1 ];
      assert( str != NULL );

	  strcpy( str, s );			// Copy instance variable values
      size = strlen( s );
   }
}					// End constructor method


string::string( const char c )

   //  Constructor for strings, cast from a character to a string
   //
   //  c:  Character to cast from
{
   str = new char[ 2 ];			// Allocate memory for the string
   assert( str != NULL );

   str[ 0 ] = c;
   str[ 1 ] = '\0';

   size = 1;
}					// End constructor method


string::string( const string& s )

   //  Constructor for strings, assign from already existing object
   //
   //  s:  String object to copy from
{
   str = new char[ s.size + 1 ];	// Allocate memory for the string
   assert( str != NULL );

   size = s.size;			// Copy instance variable values
   strcpy( str, s.str );
}					// End copy constructor


string::~string()

   //  Destructor for strings, free any memory which may be allocated
{
   if ( str ) {				// Free memory, if it exists
      delete str;
   }
}					// End destructor method


ostream& operator<<( ostream& stream, const string& s )

   //  This function allows strings to be used as part of an output stream
   //  redirection chain
   //
   //  stream:  Output stream to direct string
   //  s:       String to output
{
   return stream << s.str;
}					// End operator <<


istream& operator>>( istream& stream, string& s )

   //  This function allows strings to be used as part of an input stream
   //  redirection chain
   //
   //  stream:  Input stream to direct into string
   //  s:       String to hold input
{
   char  tmp_str[ 1024 ];		// Temporary character array


   stream.getline( tmp_str, 1024 );	// Read one line of input

   s = tmp_str;
   return stream;
}					// End operator >>
